module DUAL_PORT_RAM
#(
    parameter ADDR_WIDTH = 12,
    parameter DATA_WIDTH = 16,
    parameter RAM_SIZE = 4096
)
(
    input                       CLKA,
    input                       CLKB,
    input                       RSTN,

    input   [ADDR_WIDTH-1:0]    ADDRA,
    input   [ADDR_WIDTH-1:0]    ADDRB,
    input   [DATA_WIDTH-1:0]    DINA,
    input   [DATA_WIDTH-1:0]    DINB,
    output  [DATA_WIDTH-1:0]    DOUTA,
    output  [DATA_WIDTH-1:0]    DOUTB,

    input                       WEA,
    input                       ENA,
    input                       WEB,
    input                       ENB
);

// 指定使用Xilinx FPGA内部的Block RAM实现，如果使用其他平台实现不用理会
(* ram_style = "block"*) reg [DATA_WIDTH-1:0] ram_data [0:RAM_SIZE-1];
reg [DATA_WIDTH-1:0] douta;
reg [DATA_WIDTH-1:0] doutb;

integer i;
initial begin
    for (i=0;i<RAM_SIZE;i=i+1) begin
        ram_data[i] = {DATA_WIDTH{1'b0}};
    end
end

assign DOUTA = douta;
assign DOUTB = doutb;

always @(posedge CLKA) begin
    if(!RSTN) begin
        douta <= {DATA_WIDTH{1'b0}};
    end
    else begin
        if(ENA) douta <= ram_data[ADDRA];
        if(ENA && WEA) ram_data[ADDRA] <= DINA;
    end
end

always @(posedge CLKB) begin
    if(!RSTN) begin
        doutb <= {DATA_WIDTH{1'b0}};
    end
    else begin
        if(ENB) doutb <= ram_data[ADDRB];
        if(ENB && WEB) ram_data[ADDRB] <= DINB;
    end
end

endmodule